/*
 * Quarter.cpp
 *
 *  Created on: 06-Sep-2014
 *      Author: ali
 */

#include "Quarter.h"
#include "Field.h"
#include "NodeContainer.h"
#include "Constant.h"
extern STAT gStat;
Coordinate Quarter::GetPos()
{
	return m_cMyPos;
}
int Quarter::GetID()
{
	return m_nID;
}
Quarter::Quarter() :
		m_nID(0), m_dLen(0), m_dWidth(0), m_cMyPos(0, 0)
{
	InitLevel();
}
Quarter::Quarter(int id, double len, double width, const Coordinate& pos) :
		m_nID(id), m_dLen(len), m_dWidth(width), m_cMyPos(pos)
{
	InitLevel();
}
void Quarter::InitLevel()
{
	int nLevelCount = sizeof(m_acL) / sizeof(m_acL[0]);
	double lwidth = m_dWidth / 3;
	double x = m_cMyPos.GetXPos();
	double y = m_cMyPos.GetYPos();

	for (int i = 0; i < nLevelCount; ++i)
	{
		m_acL[i].SetLevel(i);
		m_acL[i].SetLen(m_dLen);
		m_acL[i].SetWidth(lwidth);
		Coordinate pos(x, y);
		m_acL[i].SetPos(pos);

		y += lwidth;
	}

}
bool Quarter::IsCoordinateInside(Coordinate otherPos)
{
	bool bStat = false;
	do
	{
		//check if x is in range
		if ((otherPos.GetXPos() >= m_cMyPos.GetXPos())
				&& (otherPos.GetXPos() < (m_dLen + m_cMyPos.GetXPos())))
		{
		}
		else
		{
			break;
		}
		//check if y is in range
		if ((otherPos.GetYPos() >= m_cMyPos.GetYPos())
				&& (otherPos.GetYPos() < (m_dWidth + m_cMyPos.GetYPos())))
		{
		}
		else
		{
			break;
		}
		bStat = true;
	} while (0);
	return bStat;
}
void Quarter::AddSink(Node &node)
{
	m_vectorSink.push_back(node);
	//divide the Level into CH1 CH2 CH3

	double dDist0 = (node.GetPos()).GetDistance(m_acL[0].GetPos());
	double dDist2 = (node.GetPos()).GetDistance(m_acL[2].GetPos());
	m_iIndexofCH0 = 0;
	if (dDist0 > dDist2)
	{
		m_iIndexofCH0 = 2;
	}
	int nLevelCount = sizeof(m_acL) / sizeof(m_acL[0]);

	for (int i = 0; i < nLevelCount; ++i)
	{
		m_acL[i].AddSink(node);
	}
}

bool Quarter::SendData()
{
	bool bStat = false;
	int targetCHNodeID = -1;
	int nLevelCount = sizeof(m_acL) / sizeof(m_acL[0]);

	for (int i = 0; i < nLevelCount; ++i)
	{
		int chid = m_acL[i].GetCHID();
		Node* pCH = NodeContainer::GetNode(chid);
		if (NULL != pCH)
		{
			pCH->InitDataBuffer();
		}
	}

	// start from far to sink
	do
	{
		targetCHNodeID = m_acL[1].GetCHID(); //mid
		if (targetCHNodeID == -1)
		{
			targetCHNodeID = m_acL[m_iIndexofCH0].GetCHID(); //nearest
			if (targetCHNodeID == -1)
			{
				Node& sink = GetSinkByRef();
				bStat = m_acL[2 - m_iIndexofCH0].SendData(sink); ////far to sink
				break;
			}
		}

		Node* ptargetCHNode = NodeContainer::GetNode(targetCHNodeID);
		bStat = m_acL[2 - m_iIndexofCH0].SendData(*ptargetCHNode); ////far to sink
	} while (0);

	do
	{
		targetCHNodeID = m_acL[m_iIndexofCH0].GetCHID(); //nearest
		if (targetCHNodeID == -1)
		{
			Node& sink = GetSinkByRef();
			bStat = m_acL[1].SendData(sink); ////mid level send
			break;
		}
		Node* ptargerCHNode = NodeContainer::GetNode(targetCHNodeID);
		bStat = m_acL[1].SendData(*ptargerCHNode); ////mid level send
	} while (0);

	do
	{
		Node& sink = GetSinkByRef(); //direct
		m_acL[m_iIndexofCH0].SendData(sink);
	} while (0);
	return bStat;
}
bool Quarter::SelectCH()
{
	bool bStat = false;
	int chSelectionFail = 0;

	bStat = m_acL[m_iIndexofCH0].SelectCH(); //nearest to sink
	if (false == bStat)
	{
		++chSelectionFail;
	}
	else
	{
		gStat.dCHCount++;
		Node *ch1 = m_acL[m_iIndexofCH0].GetCH();
		cout << "Quarter # " << m_nID << " Level # " << m_iIndexofCH0
				<< " Selected CH :" << *ch1 << endl;
	}
	bStat = m_acL[1].SelectCH(); //mid level
	if (false == bStat)
	{
		++chSelectionFail;
	}
	else
	{
		Node *ch1 = m_acL[1].GetCH();
		gStat.dCHCount++;
		cout << "Quarter # " << m_nID << " Level # " << 1 << " Selected CH :"
				<< *ch1 << endl;
	}
	bStat = m_acL[2 - m_iIndexofCH0].SelectCH(); ////far to sink
	if (false == bStat)
	{
		++chSelectionFail;
	}
	else
	{
		Node *pch1 = m_acL[2 - m_iIndexofCH0].GetCH();
		gStat.dCHCount++;
		cout << "Quarter # " << m_nID << " Level # " << 2 - m_iIndexofCH0
				<< " Selected CH :" << *pch1 << endl;
	}
	if (3 == chSelectionFail)
	{
		bStat = false;
	}
	else
	{
		bStat = true;
	}
	return bStat;
}
void Quarter::AddSensor(Node &node)
{
	m_vectorSensor.push_back(node.GetID());
	int nLevelCount = sizeof(m_acL) / sizeof(m_acL[0]);

	for (int i = 0; i < nLevelCount; ++i)
	{
		if (m_acL[i].IsCoordinateInside(node.GetPos()))
		{
			m_acL[i].AddSensor(node);
			return;
		}
	}
}
Node Quarter::GetSink()
{
	std::vector<Node>::iterator itSink = m_vectorSink.begin();
	Node node = *itSink;
	return node;

}
Node& Quarter::GetSinkByRef()
{
	std::vector<Node>::iterator itSink = m_vectorSink.begin();
	return *itSink;
	//return node;

}

int Quarter::GetSinkID()
{

	std::vector<Node>::iterator itSink = m_vectorSink.begin();
	if (m_vectorSink.end() != itSink)
	{
		Node node = *itSink;

		return node.GetID();
	}
	return -1;
}
Quarter::~Quarter()
{

}
ostream & operator<<(ostream &out, Quarter& q)
{
	out << endl << "Quarter ID:" << q.GetID() << " X: "
			<< (q.GetPos()).GetXPos() << " Y: " << (q.GetPos()).GetYPos()
			<< " Node Count " << q.m_vectorSensor.size() << " Sink ID "
			<< q.GetSinkID() << " Level index near to sink " << q.m_iIndexofCH0
			<< endl;

	int nLevelCount = sizeof(q.m_acL) / sizeof(q.m_acL[0]);

	for (int i = 0; i < nLevelCount; ++i)
	{
		out << q.m_acL[i];
	}
	return out;
}
